/**
 * @type {HTMLCanvasElement}
 */
function getGl({ vert, frag }) {
  const canvas = document.getElementById("canvas")
  const gl = canvas.getContext("webgl")
  // 设置清空颜色缓冲区时的颜色
  gl.clearColor(1.0, 1.0, 1.0, 1.0)

  // 清空颜色缓冲区
  gl.clear(gl.COLOR_BUFFER_BIT)

  // 初始化shader程序
  const program = initWebGL(gl, vert, frag)
  // 告诉WebGL使用我们刚刚初始化的这个程序
  gl.useProgram(program)

  return [program, gl]
}

/**
 *
 * @param {WebGLRenderingContext} gl
 * @param {string} type
 * @param {string} source
 */
function createShader(gl, type, source) {
  // 创建 shader 对象
  let shader = gl.createShader(type)
  // 往 shader 中传入源代码
  gl.shaderSource(shader, source)
  // 编译 shader
  gl.compileShader(shader)
  // 判断 shader 是否编译成功
  let success = gl.getShaderParameter(shader, gl.COMPILE_STATUS)
  if (success) {
    return shader
  }
  // 如果编译失败，则打印错误信息
  console.log(gl.getShaderInfoLog(shader))
  gl.deleteShader(shader)
}

/**
 *
 * @param {WebGLRenderingContext} gl
 * @param {WebGLShader} vertexShader
 * @param {WebGLShader} fragmentShader
 */
function createProgram(gl, vertexShader, fragmentShader) {
  // 创建 program 对象
  let program = gl.createProgram()
  // 往 program 对象中传入 WebGLShader 对象
  gl.attachShader(program, vertexShader)
  gl.attachShader(program, fragmentShader)
  // 链接 program
  gl.linkProgram(program)
  // 判断 program 是否链接成功
  let success = gl.getProgramParameter(program, gl.LINK_STATUS)
  if (success) {
    return program
  }
  // 如果 program 链接失败，则打印错误信息
  console.log(gl.getProgramInfoLog(program))
  gl.deleteProgram(program)
}
function createTexture(gl) {
  let texture = gl.createTexture()
  gl.bindTexture(gl.TEXTURE_2D, texture)
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
  gl.generateMipmap(gl.TEXTURE_2D)
  return texture
}
/**
 *
 * @param {WebGLRenderingContext} gl
 * @param {string} vertexSource
 * @param {string} fragmentSource
 */
function initWebGL(gl, vertexSource, fragmentSource) {
  // 根据源代码创建顶点着色器
  let vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexSource)
  // 根据源代码创建片元着色器
  let fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentSource)
  // 创建 WebGLProgram 程序
  let program = createProgram(gl, vertexShader, fragmentShader)

  return program
}

// 实现一个点
function realizedPoint(program, gl, point = [0.0, 0.0, 0.0]) {
  // 获取shader中a_position的地址
  const a_position = gl.getAttribLocation(program, "a_position")
  // 往a_position这个地址中传值
  gl.vertexAttrib3f(a_position, 0.0, 0.0, 0.0)
  // 开始绘制，绘制类型是gl.POINTS绘制点，0表示第一个点的索引，1表示共绘制几个点
  gl.drawArrays(gl.POINTS, 0, 1)
}

// 实现一个三角形
function realizedTriangle(
  program,
  gl,
  pointPos = [-0.5, 0.0, 0.5, 0.0, 0.0, 0.5]
) {
  const buffer = gl.createBuffer()
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
  // -----------------------------------------------------
  // 注意：这里必须采用类型化数组往WebGL传入attribute类型的数据
  // -----------------------------------------------------
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(pointPos), gl.STATIC_DRAW)
  const a_position = gl.getAttribLocation(program, "a_position")
  // 我们不再采用这种方式进行传值
  // gl.vertexAttrib3f(a_position, 0.0, 0.0, 0.0);
  // 采用vertexAttribPointer进行传值
  gl.vertexAttribPointer(
    a_position,
    2,
    gl.FLOAT,
    false,
    Float32Array.BYTES_PER_ELEMENT * 2,
    0
  )
  gl.enableVertexAttribArray(a_position)

  gl.drawArrays(gl.TRIANGLES, 0, 3)
}

// 实现一个渐变色三角形
function realizedTrianglePro(program, gl) {
  const pointPos = [-0.5, 0.0, 0.5, 0.0, 0.0, 0.5]

  const pointColor = [
    1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0,
  ]

  const buffer = gl.createBuffer()
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(pointPos), gl.STATIC_DRAW)

  const colorBuffer = gl.createBuffer()
  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer)
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(pointColor), gl.STATIC_DRAW)

  const a_position = gl.getAttribLocation(program, "a_position")
  const a_color = gl.getAttribLocation(program, "a_color")
  gl.vertexAttribPointer(
    a_position,
    2,
    gl.FLOAT,
    false,
    Float32Array.BYTES_PER_ELEMENT * 6,
    0
  )
  gl.vertexAttribPointer(
    a_color,
    4,
    gl.FLOAT,
    false,
    Float32Array.BYTES_PER_ELEMENT * 6,
    Float32Array.BYTES_PER_ELEMENT * 2
  )
  gl.enableVertexAttribArray(a_position)
  gl.enableVertexAttribArray(a_color)

  gl.drawArrays(gl.TRIANGLES, 0, 3)
}

// 绘制一个图形
function realizedRect(program, gl) {
  const pointPos = [-1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1]
  const texCoordPos = [0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1]

  const buffer = gl.createBuffer()
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(pointPos), gl.STATIC_DRAW)
  const texCoordBuffer = gl.createBuffer()
  gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer)
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoordPos), gl.STATIC_DRAW)

  const a_position = gl.getAttribLocation(program, "a_position")
  const a_texCoord = gl.getAttribLocation(program, "a_texCoord")
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
  gl.vertexAttribPointer(
    a_position,
    2,
    gl.FLOAT,
    false,
    Float32Array.BYTES_PER_ELEMENT * 2,
    0
  )
  gl.enableVertexAttribArray(a_position)

  gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer)
  gl.vertexAttribPointer(
    a_texCoord,
    2,
    gl.FLOAT,
    false,
    Float32Array.BYTES_PER_ELEMENT * 2,
    0
  )
  gl.enableVertexAttribArray(a_texCoord)
  const image = new Image()
  image.src = "../assets/0.png"
  image.onload = function () {
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1)
    createTexture(gl)
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image)
    gl.drawArrays(gl.TRIANGLES, 0, 6)
  }
}
